﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace ERF
{
    /// <summary>
    /// Represents the base effect class, which all objects drawn with ERF must utilize.
    /// </summary>
    public class EffectBase : Effect
    {
        private EffectParameter worldParameter;
        private EffectParameter viewParameter;
        private EffectParameter projectionParameter;
        private EffectParameter alphaParameter;
        private EffectParameter ambientColorParameter;
        private EffectParameter ambientIntensityParameter;
        private EffectParameter fogEnabledParameter;
        private EffectParameter fogStartParameter;
        private EffectParameter fogEndParameter;
        private EffectParameter fogColorParameter;
        private EffectParameter lightDirectionParameter;
        private EffectParameter diffuseColorParameter;
        private EffectParameter diffuseIntensityParameter;
        private EffectParameter shininessParameter;
        private EffectParameter specularColorParameter;
        private EffectParameter specularIntensityParameter;
        private EffectParameter eyePositionParameter;
        private EffectParameter viewDirectionParameter;

        /// <summary>
        /// Creates a new instance of EffectBase.
        /// </summary>
        /// <param name="device">The GraphicsDevice that this instance belongs to.</param>
        /// <param name="effect">The effect to clone.</param>
        public EffectBase(GraphicsDevice device, Effect effect)
            : base(device, effect.Clone(device))
        {
            this.InitParameters();
        }

        /// <summary>
        /// Initializes the parameter fields by fetching the corresponding shader variable parameters.
        /// </summary>
        private void InitParameters()
        {
            this.worldParameter = base.Parameters["World"];
            this.viewParameter = base.Parameters["View"];
            this.projectionParameter = base.Parameters["Projection"];
            this.alphaParameter = base.Parameters["Alpha"];
            this.ambientColorParameter = base.Parameters["AmbientColor"];
            this.ambientIntensityParameter = base.Parameters["AmbientIntensity"];
            this.fogEnabledParameter = base.Parameters["FogEnabled"];
            this.fogStartParameter = base.Parameters["FogStart"];
            this.fogEndParameter = base.Parameters["FogEnd"];
            this.fogColorParameter = base.Parameters["FogColor"];
            this.lightDirectionParameter = base.Parameters["DiffuseLightDirection"];
            this.diffuseColorParameter = base.Parameters["DiffuseColor"];
            this.diffuseIntensityParameter = base.Parameters["DiffuseIntensity"];
            this.shininessParameter = base.Parameters["SpecularPower"];
            this.specularColorParameter = base.Parameters["SpecularColor"];
            this.specularIntensityParameter = base.Parameters["SpecularIntensity"];
            this.eyePositionParameter = base.Parameters["EyePosition"];
            this.viewDirectionParameter = base.Parameters["ViewVector"];
        }

        /// <summary>
        /// Gets or sets the Alpha of the effect material.
        /// </summary>
        public float Alpha
        {
            get { return this.alphaParameter.GetValueSingle(); }
            set { this.alphaParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the color of the ambient light.
        /// </summary>
        public Vector3 AmbientColor
        {
            get
            {
                Vector4 color = this.ambientColorParameter.GetValueVector4();
                return new Vector3(color.X, color.Y, color.Z);
            }
            set { this.ambientColorParameter.SetValue(new Vector4(value, 1)); }
        }

        /// <summary>
        /// Gets or sets the intensity of the ambient light.
        /// </summary>
        public float AmbientIntensity
        {
            get { return this.ambientIntensityParameter.GetValueSingle(); }
            set { this.ambientIntensityParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the color of the diffuse light.
        /// </summary>
        public Vector3 DiffuseColor
        {
            get
            {
                Vector4 color = this.diffuseColorParameter.GetValueVector4();
                return new Vector3(color.X, color.Y, color.Z);
            }
            set { this.diffuseColorParameter.SetValue(new Vector4(value, 1)); }
        }

        /// <summary>
        /// Gets or sets the intensity of the diffuse light.
        /// </summary>
        public float DiffuseIntensity
        {
            get { return this.diffuseIntensityParameter.GetValueSingle(); }
            set { this.diffuseIntensityParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the position of the viewer.
        /// </summary>
        public Vector3 EyePosition
        {
            get { return this.eyePositionParameter.GetValueVector3(); }
            set { this.eyePositionParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the color of the fog.
        /// </summary>
        public Vector4 FogColor
        {
            get { return this.fogColorParameter.GetValueVector4(); }
            set { this.fogColorParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets a value denoting whether to render fog or not.
        /// </summary>
        public bool FogEnabled
        {
            get
            {
                float fogEnabled = this.fogEnabledParameter.GetValueSingle();
                return (fogEnabled == 1f);
            }
            set
            {
                if (value)
                    this.fogEnabledParameter.SetValue(1);
                else
                    this.fogEnabledParameter.SetValue(0);
            }
        }

        /// <summary>
        /// Gets or sets the ending distance of the fog.
        /// </summary>
        public float FogEnd
        {
            get { return this.fogEndParameter.GetValueSingle(); }
            set { this.fogEndParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the starting distance of the fog.
        /// </summary>
        public float FogStart
        {
            get { return this.fogStartParameter.GetValueSingle(); }
            set { this.fogStartParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the direction of the diffuse light.
        /// </summary>
        public Vector3 LightDirection
        {
            get { return this.lightDirectionParameter.GetValueVector3(); }
            set { this.lightDirectionParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the projection matrix.
        /// </summary>
        public Matrix Projection
        {
            get { return this.projectionParameter.GetValueMatrix(); }
            set { this.projectionParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the specular power. This affects the "shininess" of the material.
        /// </summary>
        public float SpecularPower
        {
            get { return this.shininessParameter.GetValueSingle(); }
            set { this.shininessParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the color of the specular light.
        /// </summary>
        public Vector3 SpecularColor
        {
            get
            {
                Vector4 color = this.specularColorParameter.GetValueVector4();
                return new Vector3(color.X, color.Y, color.Z);
            }
            set { this.specularColorParameter.SetValue(new Vector4(value, 1)); }
        }

        /// <summary>
        /// Gets or sets the intensity of the specular light.
        /// </summary>
        public float SpecularIntensity
        {
            get { return this.specularIntensityParameter.GetValueSingle(); }
            set { this.specularIntensityParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the view matrix.
        /// </summary>
        public Matrix View
        {
            get { return this.viewParameter.GetValueMatrix(); }
            set { this.viewParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the direction in which the viewer is looking.
        /// </summary>
        public Vector3 ViewDirection
        {
            get { return this.viewDirectionParameter.GetValueVector3(); }
            set { this.viewDirectionParameter.SetValue(value); }
        }

        /// <summary>
        /// Gets or sets the world matrix.
        /// </summary>
        public Matrix World
        {
            get { return this.worldParameter.GetValueMatrix(); }
            set { this.worldParameter.SetValue(value); }
        }
    }
}
